//
//  LGSExecutor.m
//  LogicSim
//
//  Created by Jeremy Pereira on 05/04/2012.
//  Copyright (c) 2012 Jeremy Pereira. All rights reserved.
//

#import "LGSExecutor.h"
#import "LGSNode.h"

@interface LGSExecutor ()

-(void) addNodes: (NSOrderedSet*) newNodes toTick: (TimeTick) tick;
-(NSMutableOrderedSet*) nodesAtTick: (TimeTick) tick;

@end

@implementation LGSExecutor
{
@private
    bool trace;
    bool shouldStop;
    NSMutableArray* nodesToEvaluateByTick;
}

@synthesize trace, shouldStop;

-(id) init
{
    self = [super init];
    if (self != nil)
    {
        nodesToEvaluateByTick = [[NSMutableArray alloc] init];
    }
    return self;
}

-(unsigned long) evaluateWithInitialSet: (NSMutableOrderedSet*) initialSet
               			  maxIterations: (unsigned long) maxIterations
{
    unsigned long iterations = 0; 
    [self addNodes: initialSet toTick: 0];
    while ([nodesToEvaluateByTick count] > 0 
           && ![self shouldStop] 
           && iterations < maxIterations) 
    {
        NSMutableOrderedSet* currentSet 
        	= [nodesToEvaluateByTick objectAtIndex: 0];
        while ([currentSet count] > 0
               && ![self shouldStop] 
               && iterations < maxIterations) 
        {
            LGSNode* nodeToEvaluate = [currentSet objectAtIndex: 0];
            [currentSet removeObjectAtIndex: 0];
            [nodeToEvaluate evaluateAffectedNodes: 
             [self nodesAtTick: [nodeToEvaluate gateDelay]]];
            iterations++;
            if ([self trace])
            {
                NSLog(@"%lu: nodes to evaluate %@", iterations, self);
            }
        }
        if ([currentSet count] == 0)
        {
            [nodesToEvaluateByTick removeObjectAtIndex: 0];            
        }
    }
    return iterations;
}

-(size_t) nodeCountAtTick: (TimeTick) tickNumber
{
    return [[self nodesAtTick: tickNumber] count];
}

-(void) addNodes: (NSOrderedSet*) newNodes toTick: (TimeTick) tick
{
    [[self nodesAtTick: tick] unionOrderedSet: newNodes];
}

-(void) removeAllNodes
{
    [nodesToEvaluateByTick removeAllObjects];
}


-(NSMutableOrderedSet*) nodesAtTick: (TimeTick) tick
{
    while ([nodesToEvaluateByTick count] <= tick) 
    {
        [nodesToEvaluateByTick addObject: [NSMutableOrderedSet orderedSet]];
    }
    return [nodesToEvaluateByTick objectAtIndex: tick];
}

-(NSString*) description
{
    NSMutableString* ret = [[NSMutableString alloc] init];
    TimeTick currentTick = 0;
    for (NSOrderedSet* nodesForTick in nodesToEvaluateByTick)
    {
        [ret appendFormat: @"Tick %6ld:", (long)currentTick];
        for (LGSNode* node in nodesForTick)
        {
            [ret appendFormat: @" (%@)", node];
        }
        [ret appendString: @"\n"];
        currentTick++;
    }
    return ret;
}

@end
